package com.openlogic.common.core.expression;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import com.openlogic.common.core.exception.IllegalExpressionException;
import com.openlogic.common.core.expression.Element.ElementType;

/**
 * @ClassName: ExpressionUtil
 * @Description: ExpressionUtil
 * @author weiyongpeng
 * @date 2025年2月3日 下午1:37:07
 */
public class ExpressionUtil {

	public static Map<String, Integer> operators = new HashMap<String, Integer>();

	private static Set<String> specialParams = new HashSet<String>();

	private static final String SPLITOR = "(),";

	private static final String NUMBER_CHARS = "01234567890.";

	static {
		operators.put("*", 2);
		operators.put("/", 2);

		operators.put("+", 3);
		operators.put("-", 3);

		operators.put("=", 4);
		operators.put("!=", 4);
		operators.put(">", 4);
		operators.put(">=", 4);
		operators.put("<", 4);
		operators.put("<=", 4);
		operators.put("等于", 4);
		operators.put("不等于", 4);
		operators.put("大于", 4);
		operators.put("大于等于", 4);
		operators.put("小于", 4);
		operators.put("小于等于", 4);

		operators.put("并且", 5);
		operators.put("或者", 5);
		operators.put("AND", 5);
		operators.put("OR", 5);

		operators.put("包含", 5);
		operators.put("不包含", 5);
		operators.put("IN", 5);
		operators.put("NOT IN", 5);
		operators.put("匹配", 5);
		operators.put("不匹配", 5);
		operators.put("LIKE", 5);
		operators.put("NOT LIKE", 5);

		specialParams.add("月天数");
		specialParams.add("季天数");
		specialParams.add("年天数");
		specialParams.add("月数");
		specialParams.add("当月总天数");
		specialParams.add("当季总天数");
		specialParams.add("当年总天数");
		specialParams.add("上年总天数");

	}

	public static List<Element> split(String expr) throws IllegalExpressionException {
		List<Element> elements = new ArrayList<Element>();
		int len = expr.length();
		String noAnalyze = null;
		int nai = 0;
		for (int i = 0; i < len;) {
			String ce = expr.substring(i);
			if (ce.startsWith("#")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				String var = "";
				int j = 1;
				for (; j < len - i; j++) {
					var += ce.charAt(j);
					if (ce.charAt(j) == '#') {
						break;
					}
				}
				if (j == len - i) {
					throw new IllegalExpressionException("#" + var, "dataColumnClose", i);
				}
				elements.add(new Element("#" + var, ElementType.DATACOLUMN, i));
				i += j + 1;
			} else if ("'".equals(Character.toString(ce.charAt(0)))) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				String var = "";
				int j = 1;
				for (; j < len - i; j++) {
					var += ce.charAt(j);
					if (ce.charAt(j) == '\'') {
						break;
					}
				}
				if (j == len - i) {
					throw new IllegalExpressionException("'" + var, "stringClose", i);
				}
				elements.add(new Element("'" + var, ElementType.STRING, i));
				i += j + 1;
			} else if (ce.startsWith("NOT LIKE")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((8 < len - i) ? 8 : len - i); j >= 0; j--) {
					if (operators.containsKey(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.OPERATOR, i));
						break;
					}
				}
			} else if (ce.startsWith("NOT IN")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((6 < len - i) ? 6 : len - i); j >= 0; j--) {
					if (operators.containsKey(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.OPERATOR, i));
						break;
					}
				}
			} else if (ce.startsWith("小于等于") || ce.startsWith("大于等于") || ce.startsWith("LIKE")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((4 < len - i) ? 4 : len - i); j >= 0; j--) {
					if (operators.containsKey(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.OPERATOR, i));
						break;
					}
				}
			} else if (ce.startsWith("不等于") || ce.startsWith("不匹配") || ce.startsWith("不包含") || ce.startsWith("AND")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((3 < len - i) ? 3 : len - i); j >= 0; j--) {
					if (operators.containsKey(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.OPERATOR, i));
						break;
					}
				}
			} else if (ce.startsWith("<=") || ce.startsWith(">=") || ce.startsWith("等于") || ce.startsWith("大于")
					|| ce.startsWith("小于") || ce.startsWith("并且") || ce.startsWith("或者") || ce.startsWith("OR")
					|| ce.startsWith("包含") || ce.startsWith("IN") || ce.startsWith("匹配")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((2 < len - i) ? 2 : len - i); j >= 0; j--) {
					if (operators.containsKey(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.OPERATOR, i));
						break;
					}
				}
			} else if (ce.startsWith("+") || ce.startsWith("-") || ce.startsWith("*") || ce.startsWith("/")
					|| ce.startsWith("=") || ce.startsWith(">") || ce.startsWith("<")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((1 < len - i) ? 1 : len - i); j >= 0; j--) {
					if (operators.containsKey(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.OPERATOR, i));
						break;
					}
				}
			} else if (ce.startsWith("!=")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((1 < len - i) ? 2 : len - i); j >= 0; j--) {
					if (operators.containsKey(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.OPERATOR, i));
						break;
					}
				}
			} else if (ce.startsWith("月天数") || ce.startsWith("季天数") || ce.startsWith("年天数") || ce.startsWith("月数")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((3 < len - i) ? 3 : len - i); j >= 0; j--) {
					if (specialParams.contains(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.SPECIALPARAM, i));
						break;
					}
				}
			} else if (ce.startsWith("当月总天数") || ce.startsWith("当季总天数") || ce.startsWith("当年总天数")
					|| ce.startsWith("上年总天数")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				for (int j = ((5 < len - i) ? 5 : len - i); j >= 0; j--) {
					if (specialParams.contains(ce.substring(0, j))) {
						i += j;
						elements.add(new Element(ce.substring(0, j), ElementType.SPECIALPARAM, i));
						break;
					}
				}
			} else if (ce.startsWith("同比(") || ce.startsWith("季环比(") || ce.startsWith("月环比(")
					|| ce.startsWith("较月初增长量(") || ce.startsWith("较季初增长量(") || ce.startsWith("较年初增长量(")
					|| ce.startsWith("较月初增长率(") || ce.startsWith("较季初增长率(") || ce.startsWith("较年初增长率(")
					|| ce.startsWith("完成比例(") || ce.startsWith("较目标增长量(") || ce.startsWith("同比增长量(")
					|| ce.startsWith("同比增长率(")) {
				String str = ce.substring(0, ce.indexOf("(")).trim();
				elements.add(new Element(str, ElementType.FUNCTION, nai));
				i += str.length();
			} else if (ce.startsWith("T(")) {
				elements.add(new Element("T", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("E(")) {
				elements.add(new Element("E", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("W(")) {
				elements.add(new Element("W", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("L(")) {
				elements.add(new Element("L", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("V(")) {
				elements.add(new Element("V", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("O(")) {
				elements.add(new Element("O", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("F(")) {
				elements.add(new Element("F", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("S(")) {
				elements.add(new Element("S", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("R(")) {
				elements.add(new Element("R", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("C(")) {
				elements.add(new Element("C", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("P(")) {
				elements.add(new Element("P", ElementType.FUNCTION, nai));
				i += 1;
			} else if (ce.startsWith("条件计算(")) {
				elements.add(new Element("条件计算", ElementType.FUNCTION, nai));
				i += 4;
			} else if (ce.startsWith("统计数量(")) {
				elements.add(new Element("统计数量", ElementType.FUNCTION, nai));
				i += 4;
			} else if (ce.startsWith("汇总(")) {
				elements.add(new Element("汇总", ElementType.FUNCTION, nai));
				i += 2;
			} else if (ce.startsWith(" ") || ce.startsWith("\t") || ce.startsWith("\n") || ce.startsWith("\r")) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				i++;
				elements.add(new Element(" ", ElementType.SEPARATOR, i));
			} else if (NUMBER_CHARS.contains(Character.toString(ce.charAt(0)))) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				String number = "";
				int j = 0;
				for (; j < len - i; j++) {
					if (!NUMBER_CHARS.contains(Character.toString(ce.charAt(j)))) {
						break;
					}
					number += Character.toString(ce.charAt(j));
				}
				elements.add(new Element(number, ElementType.NUMBER, i));
				i += j;
			} else if (SPLITOR.contains(Character.toString(ce.charAt(0)))) {
				if (noAnalyze != null) {
					elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
					noAnalyze = null;
				}
				elements.add(new Element(Character.toString(ce.charAt(0)), ElementType.SPLITOR, i));
				i++;
			} else {
				if (noAnalyze == null) {
					nai = i;
				}
				noAnalyze = (noAnalyze == null ? "" : noAnalyze) + Character.toString(ce.charAt(0));
				i++;
			}
		}
		if (noAnalyze != null) {
			elements.add(new Element(noAnalyze, ElementType.NOANALYZE, nai));
			noAnalyze = null;
		}
		return elements;
	}

	public static Map<String, Object> compile(List<Element> splitExprs) throws IllegalExpressionException {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		// 负符号的问题和NOANALYZE类型
		List<Element> eles = new ArrayList<Element>();
		String operator = null;
		int operatorCount = 0;
		for (int i = 0; i < splitExprs.size(); i++) {
			if (Element.ElementType.NOANALYZE == splitExprs.get(i).getType()) {
				throw new IllegalExpressionException(splitExprs.get(i).getText(), "noanalyze",
						splitExprs.get(i).getStartIndex());
			}
			if (splitExprs.get(i).getType() == ElementType.OPERATOR && "-".equals(splitExprs.get(i).getText())
					&& i < splitExprs.size() && splitExprs.get(i + 1).getType() == ElementType.NUMBER
					&& (i == 0 || splitExprs.get(i - 1).getType() == ElementType.OPERATOR
							|| splitExprs.get(i - 1).getType() == ElementType.SPLITOR
							|| splitExprs.get(i - 1).getType() == ElementType.SEPARATOR)) {
				operator = splitExprs.get(i).getText();
				operatorCount += 1;
				// continue;
			}
			Element e = splitExprs.get(i);
			if (e.getType() == ElementType.OPERATOR && operatorCount < 0) {
				e.setText(operator + e.getText());
				operator = null;
			}
//			if (operator != null) {
//				e.setText(operator + e.getText());
//				operator = null;
//			}
			eles.add(e);
		}
		List<Element> _RPNExpList = new ArrayList<Element>();
		Stack<Element> opStack = new Stack<Element>();
		Stack<Element> verifyStack = new Stack<Element>();
		List<List<Element>> funcs = new ArrayList<List<Element>>();
		Element _function = null;
		for (Element ele : eles) {
			if (Element.ElementType.DATACOLUMN == ele.getType()) {
				_RPNExpList.add(ele);
				verifyStack.push(ele);
			} else if (Element.ElementType.NUMBER == ele.getType()) {
				_RPNExpList.add(ele);
				verifyStack.push(ele);
			} else if (Element.ElementType.NOANALYZE == ele.getType()) {
				verifyStack.push(ele);
			} else if (Element.ElementType.SPECIALPARAM == ele.getType()) {
				_RPNExpList.add(ele);
				verifyStack.push(ele);
			} else if (Element.ElementType.STRING == ele.getType()) {
				_RPNExpList.add(ele);
				verifyStack.push(ele);
			} else if (Element.ElementType.OPERATOR == ele.getType()) {
				if (opStack.empty()) {
					opStack.push(ele);
				} else {
					boolean doPeek = true;
					while (doPeek & !opStack.empty()) {
						Element topEle = opStack.peek();
						if (Element.ElementType.OPERATOR == topEle.getType()) {
							if (operators.get(topEle.getText()) > operators.get(ele.getText())) {
								opStack.push(ele);
								doPeek = false;
							} else if (operators.get(topEle.getText()).equals(operators.get(ele.getText()))) {
								Element verityEle = verifyOperator(topEle, verifyStack);
								verifyStack.push(verityEle);
								opStack.pop();
								_RPNExpList.add(topEle);
							} else {
								Element verityEle = verifyOperator(topEle, verifyStack);
								verifyStack.push(verityEle);
								opStack.pop();
								_RPNExpList.add(topEle);
							}
						} else if (Element.ElementType.FUNCTION == topEle.getType()) {
							opStack.push(ele);
							doPeek = false;
						} else if (Element.ElementType.SPLITOR == topEle.getType()) {
							opStack.push(ele);
							doPeek = false;
						}
					}
					if (doPeek && opStack.empty()) {
						opStack.push(ele);
					}
				}
			} else if (Element.ElementType.SPLITOR == ele.getType()) {
				if ("(".equals(ele.getText())) {
					// 函数的左括号
					if (_function != null) {
						verifyStack.push(ele);
						_RPNExpList.add(ele);
						// 将"("及临时缓存的函数压入操作符栈,括号在前
						opStack.push(ele);
						opStack.push(_function);
						_function = null;
					} else {
						opStack.add(ele);
					}
				} else if (")".equals(ele.getText())) {
					boolean doPop = true;
					while (doPop && !opStack.empty()) {
						Element topEle = opStack.pop();
						if (Element.ElementType.OPERATOR == topEle.getType()) {
							Element result = verifyOperator(topEle, verifyStack);
							verifyStack.push(result);
							_RPNExpList.add(topEle);
						} else if (Element.ElementType.FUNCTION == topEle.getType()) {
							Element result = verifyFunction(topEle, verifyStack, funcs);
							verifyStack.push(result);
							_RPNExpList.add(ele);
							_RPNExpList.add(topEle);
						} else if ("(".equals(topEle.getText())) {
							doPop = false;
						}
					}
					if (doPop && opStack.empty()) {
						throw new IllegalExpressionException(ele.getText(), "leftBracketLack", ele.getStartIndex());
					}
				} else if (",".equals(ele.getText())) {
					boolean doPeek = true;
					while (doPeek && !opStack.empty()) {
						Element topEle = opStack.peek();
						if (Element.ElementType.FUNCTION == topEle.getType()) {
							doPeek = false;
						} else if (Element.ElementType.OPERATOR == topEle.getType()) {
							opStack.pop();
							Element result = verifyOperator(topEle, verifyStack);
							verifyStack.push(result);
							_RPNExpList.add(topEle);
						} else if (Element.ElementType.SPLITOR == topEle.getType()) {
							throw new IllegalExpressionException(ele.getText(), "comma", ele.getStartIndex());
						}
					}
				}
			} else if (Element.ElementType.FUNCTION == ele.getType()) {
				_function = ele;
			}
		}
		// 将操作栈内剩余的操作符放入逆波兰式队列
		while (!opStack.empty()) {
			Element topEle = opStack.pop();
			if (Element.ElementType.OPERATOR == topEle.getType()) {
				// 执行操作符校验
				Element result = verifyOperator(topEle, verifyStack);
				// 把校验结果压入检验栈
				verifyStack.push(result);
				_RPNExpList.add(topEle);
			} else if (Element.ElementType.FUNCTION == topEle.getType()) {
				throw new IllegalExpressionException(topEle.getText(), "functionClose", topEle.getStartIndex());
			} else if ("(".equals(topEle.getText())) {
				throw new IllegalExpressionException(topEle.getText(), "rightBracketLack", topEle.getStartIndex());
			}
		}

		if (verifyStack.size() != 1) {
			StringBuffer errorBuffer = new StringBuffer("");
			int position = -1;
			while (!verifyStack.empty()) {
				Element topEle = verifyStack.pop();
				errorBuffer.append("'").append(topEle.toString()).append("',");
				if (position == -1) {
					position = topEle.getStartIndex();
				}
			}
			throw new IllegalExpressionException(errorBuffer.toString(), "operatorlack", position);
		} else {
			Element e = verifyStack.pop();
			resultMap.put("result", e);
		}
		resultMap.put("funcs", funcs);
		resultMap.put("rpn", _RPNExpList);
		return resultMap;
	}

	/**
	 * 验证操作符
	 * 
	 * @param ele
	 * @param vertifyStack
	 * @return
	 * @throws IllegalExpressionException
	 */
	public static Element verifyOperator(Element ele, Stack<Element> verifyStack) throws IllegalExpressionException {
		List<Element> args = new ArrayList<Element>();
		String t = "";
		for (int i = 0; i < 2; i++) {
			if (!verifyStack.empty()) {
				Element e = verifyStack.pop();
				args.add(e);
				if (operators.get(ele.getText()) <= 4) {
					if (Element.ElementType.NUMBER != e.getType() && Element.ElementType.SPECIALPARAM != e.getType()
							&& Element.ElementType.DATACOLUMN != e.getType()) {
						throw new IllegalExpressionException(ele.getText(), "operatorType", ele.getStartIndex());
					}
				} else {
					if (Element.ElementType.BOOLEAN != e.getType()) {
						throw new IllegalExpressionException(ele.getText(), "operatorType", ele.getStartIndex());
					}
				}
			} else {
				throw new IllegalExpressionException(ele.getText(), "argCount", ele.getStartIndex());
			}
		}
		t = args.get(1).getText() + ele.getText() + args.get(0).getText();
		if (operators.get(ele.getText()) >= 4) {
			return new Element(t, ElementType.BOOLEAN, ele.getStartIndex());
		} else {
			return new Element(t, ElementType.NUMBER, ele.getStartIndex());
		}
	}

	/**
	 * 验证函数
	 * 
	 * @param ele
	 * @param verifyStack
	 * @return
	 * @throws IllegalExpressionException
	 */
	public static Element verifyFunction(Element ele, Stack<Element> verifyStack, List<List<Element>> funcs)
			throws IllegalExpressionException {
		List<Element> funcArg = new ArrayList<Element>();
		if (!verifyStack.empty()) {
			List<Element> args = new ArrayList<Element>();
			boolean doPop = true;
			while (doPop && !verifyStack.empty()) {
				Element e = verifyStack.pop();
				funcArg.add(e);
				if ("(".equals(e.getText())) {
					doPop = false;
				} else {
					args.add(e);
				}
			}
			if ("T".equals(ele.getText())) {
				if (args.size() < 1) {
					throw new IllegalExpressionException(ele.getText(), "tfunctionargscount", ele.getStartIndex());
				}
			} else if ("P".equals(ele.getText())) {
				if (args.size() < 1) {
					throw new IllegalExpressionException(ele.getText(), "pfunctionargscount", ele.getStartIndex());
				}
			} else if ("条件计算".equals(ele.getText())) {
				if (args.size() < 3 || args.size() % 2 != 1) {
					throw new IllegalExpressionException(ele.getText(), "iffunctionargscount", ele.getStartIndex());
				}
				for (int i = args.size() - 1; i >= 0; i--) {
					if (i != 0 && i % 2 == 0 && Element.ElementType.BOOLEAN != args.get(i).getType()) {
						throw new IllegalExpressionException(ele.getText(), "iffunctionfirstargsboolean",
								ele.getStartIndex());
					} else if ((i == 0 || i % 2 == 1) && Element.ElementType.NUMBER != args.get(i).getType()) {
						throw new IllegalExpressionException(ele.getText(), "iffunctionfirstargsnumber",
								ele.getStartIndex());
					}
				}
			} else if ("统计数量".equals(ele.getText())) {
				if (args.size() != 1) {
					throw new IllegalExpressionException(ele.getText(), "cfunctionargscount", ele.getStartIndex());
				}
				if (Element.ElementType.DATACOLUMN != args.get(0).getType()
						&& Element.ElementType.NUMBER != args.get(0).getType()) {
					throw new IllegalExpressionException(ele.getText(), "cfunctionargstype", ele.getStartIndex());
				}
			} else if ("汇总".equals(ele.getText())) {
				if (args.size() != 1) {
					throw new IllegalExpressionException(ele.getText(), "sumfunctionargscount", ele.getStartIndex());
				}
			}
		} else {
			throw new IllegalExpressionException(ele.getText(), "functionFull", ele.getStartIndex());
		}
		funcArg.add(ele);
		funcs.add(funcArg);
		return new Element(ele.getText(), ElementType.NUMBER, ele.getStartIndex());
	}

}
